package com.yjzx.care;

import com.yjzx.care.base.*;
import com.yjzx.care.functional.ToBoolFunction;

import java.util.function.Consumer;
import java.util.function.Function;

/**
 * @author yjzx
 * @date 2023/12/25
 * @description for循环
 */
public final class LoopFor<T> extends BaseLoop implements ValueGetSet<T> {
    public static class LoopForBuilder<T> implements LoopBuilder {
        protected LoopForBuilder() {
        }

        private Value<T> value;
        private ToBoolFunction<T> judge;
        private Function<T, T> judgeUpdater;
        private Consumer<LoopFor<T>> loopBody;

        /**
         * 必要属性填充
         *
         * @param value    变量初始化
         * @param judge    条件判断输入
         * @param loopBody 循环体
         * @return 本身
         */
        public LoopForBuilder<T> set(T value, ToBoolFunction<T> judge, Function<T, T> judgeUpdater, Consumer<LoopFor<T>> loopBody) {
            this.value = Value.of(value);
            this.judge = judge;
            this.judgeUpdater = judgeUpdater;
            this.loopBody = loopBody;
            return this;
        }
        public LoopFor<T> setAndBuild(T value, ToBoolFunction<T> judge, Function<T, T> judgeUpdater, Consumer<LoopFor<T>> loopBody) {
            this.value = Value.of(value);
            this.judge = judge;
            this.judgeUpdater = judgeUpdater;
            this.loopBody = loopBody;
            return build();
        }

        /**
         * 初始变量
         *
         * @param value 初始变量
         * @return
         */
        public LoopForBuilder<T> withValue(T value) {
            this.value = Value.of(value);
            return this;
        }

        /**
         * 条件判断
         *
         * @param judge 条件判断
         * @return
         */
        public LoopForBuilder<T> withJudge(ToBoolFunction<T> judge) {
            this.judge = judge;
            return this;
        }

        /**
         * 条件更新
         *
         * @param judgeUpdater 条件更新
         * @return
         */
        public LoopForBuilder<T> withJudgeUpdater(Function<T, T> judgeUpdater) {
            this.judgeUpdater = judgeUpdater;
            return this;
        }

        /**
         * 循环体
         *
         * @param loopBody 循环体
         * @return
         */
        public LoopForBuilder<T> withLoopBody(Consumer<LoopFor<T>> loopBody) {
            this.loopBody = loopBody;
            return this;
        }


        @Override
        public LoopFor<T> build() {
            if (this.value == null) {
                this.value = Value.of(null);
            }
            if (this.judge == null) {
                this.judge = Constant.judgeObjToTrue();
            }
            if (this.judgeUpdater == null) {
                this.judgeUpdater = Function.identity();
            }
            if (this.loopBody == null) {
                return new LoopFor<>(value, judge, judgeUpdater, Constant.loopBody());
            }
            return new LoopFor<>(value, judge, judgeUpdater, loopBody);
        }
    }

    /**
     * 变量
     */
    private final Value<T> value;

    LoopFor() {
        this.value = Value.of(null);
    }

    public static class ForParam<T> {
        T t;
        ToBoolFunction<T> judge;
        Function<T, T> judgeUpdate;

        public ForParam(T t, ToBoolFunction<T> judge, Function<T, T> judgeUpdate) {
            this.t = t;
            this.judge = judge;
            this.judgeUpdate = judgeUpdate;
        }
    }

    public LoopFor<T> loopBody(ForParam<T> param, Consumer<LoopFor<T>> loopBody) {
        this.value.set(param.t);
        this.loopBody0(param.judge, param.judgeUpdate, loopBody);
        return this;
    }

    public LoopFor<T> loopBody(T t, ToBoolFunction<T> judge, Function<T, T> judgeUpdate, Consumer<LoopFor<T>> loopBody) {
        this.value.set(t);
        this.loopBody0(judge, judgeUpdate, loopBody);
        return this;
    }

    private LoopFor(Value<T> value, ToBoolFunction<T> judge, Function<T, T> judgeUpdate, Consumer<LoopFor<T>> loopBody) {
        this.value = value;
        loopBody(value.get(), judge == null ? x -> true : judge, judgeUpdate,
                loopBody == null ? x -> {
                } : loopBody);
    }


    /**
     * 循环执行
     *
     * @param judge       判断条件
     * @param judgeUpdate 更新变量
     * @param loopBody    循环体
     */
    private void loopBody0(ToBoolFunction<T> judge, Function<T, T> judgeUpdate, Consumer<LoopFor<T>> loopBody) {
        this.isLoop();
        while (this.isBreak() && judge.apply(this.get())) {
            loopBody.accept(this);
            set(judgeUpdate);
        }
        this.toBreak();
    }

    @Override
    public void set(T value) {
        this.value.set(value);
        ;
    }

    @Override
    public T get() {
        return this.value.get();
    }
}
